#include "mytypes.h"


namespace poly
{
	const float PI = 3.1415926535897932384626433832795;
	const float TWO_PI = 6.283185307179586476925286766559;
	float33::operator float* ()
	{
		return &f[0][0];
	}

	float33::operator float const * () const
	{
		return &f[0][0];
	}

	float33& float33::operator*=( float33 const & m )
	{
		return (*this)=(*this)*m;
	}

	float33& float33::operator+=( float33 const & m )
	{
		rowx += m.rowx;
		rowy += m.rowy;
		rowz += m.rowz;

		return (*this);
	}

	float33& float33::operator-=( float33 const & m )
	{
		rowx -= m.rowx;
		rowy -= m.rowy;
		rowz -= m.rowz;

		return (*this);
	}

	float33& float33::operator*=( float s )
	{
		rowx *= s;
		rowy *= s;
		rowz *= s;

		return *this;
	}

	float33& float33::operator/=( float s )
	{
		return (*this) *= 1/s;
	}

	float33 float33::operator+() const
	{
		return (*this);
	}

	float33 float33::operator-() const
	{
		float33 out;
		out.rowx = -rowx;
		out.rowy = -rowy;
		out.rowz = -rowz;
		
		return out;
	}

	float33 float33::operator*( float33 const & m ) const
	{
		float33 out;

		out.rowx = rowx * m;
		out.rowy = rowy * m;
		out.rowz = rowz * m;

		return out;
	}

	float33 float33::operator+( float33 const & m ) const
	{
		float33 out = (*this);
		out += m;
		return out;
	}

	float33 float33::operator-( float33 const & m ) const
	{
		float33 out = (*this);
		out -= m;
		return out;
	}

	float33 float33::operator*( float s ) const
	{
		float33 out = (*this);
		out *= s;
		return out;
	}

	float33 float33::operator/( float s ) const
	{
		float33 out = (*this);
		out /= s;
		return out;
	}



	float33 operator*( float s, float33 const & m )
	{
		float33 out = m;
		out.rowx *= s;
		out.rowy *= s;
		out.rowz *= s;

		return out;
	}

	float3 operator*( float3 const &vec, float33 const & mat )
	{
		return vec[0]*mat.rowx + vec[1]*mat.rowy + vec[2]*mat.rowz;
	}

	float3 zero3()
	{
		float3 out;
		out.x = 0;
		out.y = 0;
		out.z = 0;

		return out;
	}

	float4 zero4()
	{
		float4 out;
		out.x = 0;
		out.y = 0;
		out.z = 0;
		out.w = 0;

		return out;
	}

	float33 zero33()
	{
		float33 out;
		out.rowx = zero3();
		out.rowy = zero3();
		out.rowz = zero3();

		return out;
	}

	float44 zero44()
	{
		float44 out;
		for( int i = 0; i < 4; i++ )
			for( int j = 0; j < 4; j++ )
				out.m[i][j] = 0;
		return out;
	}

	float33 identity33()
	{
		float33 out = zero33();
		out.xx = 1;
		out.yy = 1;
		out.zz = 1;

		return out;
	}

	float33 smallRotation( float3 rot )
	{
		float33 out = identity33();
		float33 c = crossing( rot );
		
		out += c;
		out.rowx = normalize( out.rowx );
		out.rowy = normalize( out.rowy );
		out.rowz = cross( out.rowx, out.rowy );

		return out;
	}

	float33 rotationAxis( float3 axis, float angle )
	{
		float cs = cos(angle);
		float sn = sin(angle);

		return
			+ identity33()*cs
			+ crossing( axis ) * sn
			+ projection( axis )*( 1 - cs );
	}

	float44 identity44()
	{
		float44 out;
		D3DXMatrixIdentity( &out );
		return out;
	}

	float length( float3 const & vec )
	{
		return D3DXVec3Length( &vec );
	}

	float lengthSq( float3 const & vec )
	{
		return D3DXVec3LengthSq( &vec );
	}

	float3 normalize( float3 const & vec )
	{
		float3 out;
		D3DXVec3Normalize( &out, &vec );
		return out;
	}

	float dot( float3 const &vec1, float3 const &vec2 )
	{
		return D3DXVec3Dot( &vec1, &vec2 );
	}

	float3 cross( float3 const &vec1, float3 const &vec2 )
	{
		float3 out;
		D3DXVec3Cross( &out, &vec1, &vec2 );
		return out;
	}

	bool rightHanded( float3 const &a, float3 const &b, float3 const &c )
	{
		float3 ab = b - a;
		float3 bc = c - b;

		return dot(cross(ab,bc),float3(0,0,1)) > 0.f;
	}

	float33 crossing( float3 const &vec )
	{
		float33 out;

		out.xx = +0;
		out.xy = +vec.z;
		out.xz = -vec.y;

		out.yx = -vec.z;
		out.yy = +0;
		out.yz = +vec.x;

		out.zx = +vec.y;
		out.zy = -vec.x;
		out.zz = +0;

		return out;
	}

	float33 projection( float3 const & vec )
	{
		float33 out;

		float x = vec[0], y = vec[1], z = vec[2];

		out.xx = x*x;
		out.xy = x*y;
		out.xz = x*z;

		out.yx = y*x;
		out.yy = y*y;
		out.yz = y*z;

		out.zx = z*x;
		out.zy = z*y;
		out.zz = z*z;

		return out/length(vec);
	}

	float determinant( float33 const & mat )
	{
		return dot( mat.rowx, cross(mat.rowy, mat.rowz) );
	}

	float33 transpose( float33 const & mat )
	{
		float33 out;
		out.xx = mat.xx;
		out.xy = mat.yx;
		out.xz = mat.zx;

		out.yx = mat.xy;
		out.yy = mat.yy;
		out.yz = mat.zy;

		out.zx = mat.xz;
		out.zy = mat.yz;
		out.zz = mat.zz;

		return out;
	}

	float33 inverse( float33 const & mat )
	{
		float33 out;

		float33 tp = transpose( mat );

		out.rowx = + cross( tp.rowy, tp.rowz );
		out.rowy = - cross( tp.rowx, tp.rowz );
		out.rowz = + cross( tp.rowx, tp.rowy );

		out /= determinant( mat );

		return out;
	}

	float3 transformNormal( float3 const & v, float44 const & mat )
	{
		float3 out;
		out = * D3DXVec3TransformNormal( &out, &v, &mat );
		return out;
	}

	float3 transformCoord( float3 const & v, float44 const & mat )
	{
		float3 out;
		out = * D3DXVec3TransformCoord( &out, &v, &mat );
		return out;
	}

	float44 augment( float33 const & mat )
	{
		float44 out = zero44();
		for( int i = 0; i < 3; i++ )
			for( int j = 0; j < 3; j++ )
				out.m[i][j] = mat.f[i][j];
		out.m[3][3] = 1;

		return out;
	}

	float44 translation( float3 const & vec )
	{
		float44 out;
		out = * D3DXMatrixTranslation( &out, vec.x, vec.y, vec.z );
		return out;
	}

	float44 lookAtLH( float3 eye, float3 at, float3 up )
	{
		float44 out;
		out = *D3DXMatrixLookAtLH( & out, &eye, &at, &up );
		return out;
	}

	float44 lookAtRH( float3 eye, float3 at, float3 up )
	{
		float44 out;
		out = *D3DXMatrixLookAtRH( & out, &eye, &at, &up );
		return out;
	}

	float44 orthoLH( float w, float h, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixOrthoLH( & out, w, h, zn, zf );
		return out;
	}

	float44 orthoRH( float w, float h, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixOrthoRH( & out, w, h, zn, zf );
		return out;
	}

	float44 orthoOffCenterLH( float l, float r, float b, float t, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixOrthoOffCenterLH( & out, l, r, b, t, zn, zf );
		return out;
	}

	float44 orthoOffCenterRH( float l, float r, float b, float t, float zn, float zf ){
		float44 out;
		out = *D3DXMatrixOrthoOffCenterRH( & out, l, r, b, t, zn, zf );
		return out;
	}

	float44 perspectiveLH( float w, float h, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixPerspectiveLH( & out, w, h, zn, zf );
		return out;
	}

	float44 perspectiveRH( float w, float h, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixPerspectiveRH( & out, w, h, zn, zf );
		return out;
	}

	float44 perspectiveFovLH( float fovy, float aspect, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixPerspectiveFovLH( & out, fovy, aspect, zn, zf );
		return out;
	}

	float44 perspectiveFovRH( float fovy, float aspect, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixPerspectiveFovRH( & out, fovy, aspect, zn, zf );
		return out;
	}

	float44 perspectiveOffCenterLH( float l, float r, float b, float t, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixPerspectiveOffCenterLH( & out, l, r, b, t, zn, zf );
		return out;
	}

	float44 perspectiveOffCenterRH( float l, float r, float b, float t, float zn, float zf )
	{
		float44 out;
		out = *D3DXMatrixPerspectiveOffCenterRH( & out, l, r, b, t, zn, zf );
		return out;
	}


	void transformRay(ray3* ray, float44* T)
	{
		D3DXVec3TransformCoord(&ray->origin, &ray->origin, T);
		D3DXVec3TransformNormal(&ray->direction, &ray->direction, T);
	}

} // end of poly
